home *** CD-ROM | disk | FTP | other *** search
/ Developer CD Series 1996 January: Mac OS SDK / Dev.CD Jan 96 SDK / Dev.CD Jan 96 SDK1.toast / Development Kits (Disc 1) / QuickDraw™ GX / Programming Stuff / Sample Code / Graphics Samples / Test Cubics (cubic to quad) ƒ / TestCubics.c < prev    next >
Encoding:
C/C++ Source or Header  |  1995-04-10  |  19.2 KB  |  957 lines  |  [TEXT/MPS ]

  1. /*---------------------------------------------------------------------------------------------
  2. FILENAME
  3.     TestClip.c
  4.     
  5. DESCRIPTION
  6.     This module is used to test that the clipping code works [correctly].  It puts up a window
  7.     and allows the user to enter polygons and to have them clipped.
  8.     
  9. COPYRIGHT
  10.     ©1992 Copyright Apple Computer, Inc.
  11.     All rights reserved.
  12.     
  13. ---------------------------------------------------------------------------------------------*/
  14.  
  15. #include "TestCubics.h"
  16. #include <Strings.h>
  17.  
  18. Cursor gHandCurs;
  19. Boolean gPolyMode;
  20. short        gFileRef;
  21. long        gcount = 0;
  22. long        gticks = 0;
  23.  
  24. long        gpointcount = 0;
  25. long        gquadcount = 0;
  26.  
  27. long        geindx = 2;
  28. extended    gerror = 0.25;
  29.  
  30. short        gcurrent = 0;
  31.  
  32. gxGraphicsClient gClient;
  33.  
  34. #pragma segment Main
  35. void main(void)
  36. {
  37.     Initialize();
  38.     EventLoop();
  39. }
  40.  
  41. #pragma segment Main
  42. void EventLoop(void)
  43. {
  44.     Boolean            gotEvent;
  45.     EventRecord     event;
  46.     short            cursFlag;
  47.  
  48.     cursFlag = kCursInit;
  49.     
  50.     do
  51.         {
  52.             SystemTask();
  53.             gotEvent = GetNextEvent(everyEvent,&event);
  54.                 
  55.             if(gotEvent)
  56.                 {
  57.                     AdjustCursor(&event,&cursFlag);
  58.                     DoEvent(&event,&cursFlag);
  59.                 }
  60.             else
  61.                 {
  62.                     AdjustCursor(&event,&cursFlag);
  63.                     /* do Idle stuff */
  64.                 }
  65.         }while(true);
  66. }
  67.  
  68. #pragma segment Main
  69. void DoEvent(EventRecord *event,
  70.                          short *cursFlag)
  71. {
  72.     short         part;
  73.     WindowPtr     window;
  74.     char         key;
  75.     
  76.     switch(event->what)
  77.         {
  78.             case nullEvent:
  79.                 AdjustCursor(event,cursFlag);
  80.                 break;
  81.                 
  82.             case mouseDown:
  83.                 part = FindWindow(event->where,&window);
  84.                 
  85.                 switch(part)
  86.                     {
  87.                         case inMenuBar:
  88.                             AdjustMenus();
  89.                             DoMenuCommand(MenuSelect(event->where));
  90.                             break;
  91.                         
  92.                         case inSysWindow:
  93.                             SystemClick(event,window);
  94.                             break;
  95.                         
  96.                         case inContent:
  97.                             if(window!=FrontWindow())
  98.                                 SelectWindow(window);
  99.                             else
  100.                                 DoContentClick(window,event,cursFlag);
  101.                             break;
  102.                             
  103.                         case inDrag:
  104.                             DragWindow(window,event->where,&qd.screenBits.bounds);
  105.                             break;
  106.                         
  107.                         case inGoAway:
  108.                             if(TrackGoAway(window,event->where))
  109.                                 DoCloseWindow(window);        //  Quit
  110.                             break;
  111.                             
  112.                         case inGrow:
  113.                             DoGrowWindow(window,event);
  114.                             break;
  115.                         
  116.                         case inZoomIn:
  117.                         case inZoomOut:
  118.                             if(TrackBox(window,event->where,part))
  119.                                 DoZoomWindow(window,part);
  120.                             break;
  121.                     }
  122.                 break;
  123.             
  124.             case keyDown:
  125.                 key = event->message & charCodeMask;
  126.                 if(event->modifiers & cmdKey)
  127.                     {
  128.                         AdjustMenus();
  129.                         DoMenuCommand(MenuKey(key));
  130.                     }
  131.                 break;
  132.                 
  133.             case activateEvt:
  134.                 break;
  135.             
  136.             case updateEvt:
  137.                 DoUpdate((WindowPtr) event->message);
  138.                 break;
  139.             
  140.         }
  141. }
  142.  
  143. #pragma segment Main
  144. void AdjustCursor(EventRecord *event,
  145.                                     short *cursFlag)
  146. {
  147.     WindowPtr    window;
  148.     RgnHandle contRgn;
  149.     RgnHandle growRgn;
  150.     Rect            growRect;
  151.     
  152.     window = FrontWindow();
  153.     if(!IsDAWindow(window))
  154.         {
  155.             contRgn = NewRgn();
  156.             growRgn = NewRgn();
  157.             
  158.             if(IsAppWindow(window))
  159.                 {
  160.                     CopyRgn(((WindowPeek)window)->contRgn,contRgn);
  161.                     
  162.                     growRect = (*((WindowPeek)window)->contRgn)->rgnBBox;
  163.                     growRect.top = growRect.bottom - kGrowBHeight;
  164.                     growRect.left = growRect.right - kGrowBWidth;
  165.                     
  166.                     SetPort(window);
  167.                     
  168.                     RectRgn(growRgn,&growRect);
  169.                     
  170.                     SetOrigin(-window->portBits.bounds.left,
  171.                                         -window->portBits.bounds.top);
  172.                     
  173.                     DiffRgn(contRgn,growRgn,contRgn);
  174.                     SetOrigin(0,0);
  175.                 }
  176.                                 
  177.                 if(PtInRgn(event->where,contRgn))
  178.                     {
  179.                         if(event->modifiers & optionKey)
  180.                             {
  181.                                 // do the hand
  182.                                 if(*cursFlag != kCursHand)
  183.                                     {
  184.                                         SetCursor(&gHandCurs);
  185.                                         *cursFlag = kCursHand;
  186.                                     }
  187.                             }
  188.                         else
  189.                             {
  190.                                 if(*cursFlag != kCursCross)
  191.                                     {
  192.                                         SetCursor(*GetCursor(crossCursor));
  193.                                         *cursFlag = kCursCross;
  194.                                     }
  195.                             }
  196.                     }
  197.                 else
  198.                     {
  199.                         SetCursor(&qd.arrow);
  200.                         *cursFlag = kCursArrow;
  201.                     }
  202.                 DisposeRgn(growRgn);
  203.                 DisposeRgn(contRgn);
  204.         }
  205.     else
  206.         {
  207.             if(*cursFlag != kCursArrow)
  208.                 {
  209.                     SetCursor(&qd.arrow);
  210.                     *cursFlag = kCursArrow;
  211.                 }
  212.         }
  213. }
  214. #pragma segment Main
  215. void DoGrowWindow(WindowPtr window,
  216.                                     EventRecord *event)
  217. {
  218.     long        growResult;
  219.     Rect        tempRect;
  220.     DocumentPeek doc;
  221.     
  222.     tempRect = qd.screenBits.bounds;
  223.     tempRect.left = kMinDocSize;
  224.     tempRect.top = kMinDocSize;
  225.     
  226.     growResult = GrowWindow(window, event->where, &tempRect);
  227.  
  228.     if (growResult!=0) 
  229.         {
  230.             doc = (DocumentPeek) window;
  231.             SizeWindow(window, LoWrd(growResult), HiWrd(growResult), true);
  232.             ResizeWindow(window);
  233.     }
  234. }
  235. #pragma segment Main
  236. void DoZoomWindow(WindowPtr window,
  237.                                     short part)
  238. {
  239.     ZoomWindow(window, part, window == FrontWindow());
  240.     ResizeWindow(window);
  241. }
  242.  
  243. #pragma segment Main
  244. void ResizeWindow(WindowPtr window)
  245. {
  246.     InvalRect(&window->portRect);
  247. }
  248.  
  249. #pragma segment Main
  250. void DoUpdate(WindowPtr    window)
  251. {
  252.     if (IsAppWindow(window)) 
  253.         {
  254.             BeginUpdate(window);
  255.             if (! EmptyRgn(window->visRgn))
  256.                 DrawWindow(window);
  257.             EndUpdate(window);
  258.         }
  259. }
  260.  
  261. #pragma segment Main
  262. void DoContentClick(WindowPtr      window,
  263.                                         EventRecord *event,
  264.                                         short                *)
  265. {
  266.     DocumentPeek     doc;
  267.  
  268.     Point        orgPoint;
  269.  
  270.     long        pinVal;
  271.     Rect        pinRect;
  272.     Rect        limitRect;
  273.     
  274.     long        indx;
  275.     
  276.     SetWorkRect(window,&pinRect,&limitRect);
  277.     
  278.     orgPoint = event->where;
  279.     GlobalToLocal(&orgPoint);        // now in local coordinates
  280.         
  281.     pinVal = PinRect(&pinRect,orgPoint);
  282.     orgPoint.h = LoWrd(pinVal);
  283.     orgPoint.v = HiWrd(pinVal);
  284.     
  285.     // convert the gxPoint to fixed gxPoint units and check to see if it
  286.     // is hitting any of the handles off the cubic and re-draw them
  287.     
  288.     doc = (DocumentPeek) window;
  289.     
  290.     // check to see if we have clicked on one of the control points
  291.  
  292.     {
  293.         gxPoint     *dataPtr;
  294.         
  295.         Boolean            found = false;
  296.     
  297.         gcurrent = (-1);            // this is to know if we clicked on nothing
  298.     
  299.         HLockHi((Handle) doc->data );
  300.     
  301.         dataPtr =(gxPoint *) *doc->data;
  302.         
  303.         for( indx = 0; indx < gpointcount; ++indx )
  304.             {                        
  305.                 gcurrent = indx;
  306.  
  307.                 if( DoCubicDrag( dataPtr, orgPoint, doc ) )
  308.                     {            
  309.                         found = true;
  310.                         break;
  311.                     }                
  312.             }
  313.     
  314.         HUnlock((Handle) doc->data );
  315.  
  316.         if( found == false )
  317.             {
  318.                 Handle        dataHdl = (Handle) doc->data;
  319.                                 
  320.                 // ## for now we just add one gxPoint
  321.                 
  322.                 SetHandleSize( dataHdl, ( doc->count + 1 ) * sizeof( gxPoint ) );
  323.                 
  324.                 if( MemError() != noErr ) goto FailedToAddPoint;
  325.                 // now store the gxPoint
  326.                 
  327.                 {
  328.                     gxPoint *dataPtr = & (*(gxPoint **)dataHdl)[ doc->count ];
  329.                     
  330.                     dataPtr->x = ff( orgPoint.h );
  331.                     dataPtr->y = ff( orgPoint.v );
  332.                     
  333.                     DrawControlHandle( dataPtr );
  334.                 }
  335.                 
  336.                 // increase the count
  337.                 
  338.                 doc->count += 1;
  339.                 gpointcount = doc->count;
  340.                 gcurrent = ( ( gpointcount - 1 ) / 3 ) * 3;
  341.  
  342.                 DrawCubicNumbers( doc );
  343.                 
  344.                 // if this makes an entirely new cubic then draw the gxCurve
  345.                 
  346.                 if( ( doc->count == 4 ) || ( ( 4 < doc->count ) && ( ( doc->count - 4 ) % 3 ) == 0 ) )
  347.                     DrawCurves( doc->data );
  348.             }
  349.     }    
  350.  
  351. FailedToAddPoint:;
  352.  
  353. }
  354.     
  355. #pragma segment Main
  356.  
  357. short DoCubicDrag( gxPoint *dataPtr, Point    start, DocumentPeek doc )
  358. {
  359.     gxRectangle        box;
  360.     
  361.     gxPoint        *where;
  362.     
  363.     where = & dataPtr[ gcurrent ];
  364.         
  365.     // first check to see if the start gxPoint is near the handle
  366.     
  367.     box.left = ff( start.h - 2 );
  368.     box.top = ff( start.v - 2 );
  369.     box.right = ff( start.h + 2 );
  370.     box.bottom = ff( start.v + 2 );
  371.     
  372.     if( GXTouchesRectanglePoint( &box, where ) != false )
  373.         {
  374.             gxShape        sh;
  375.             gxShape        sh2;
  376.  
  377.             gxColor        tempcolor;
  378.             gxColor        tempcolor2;
  379.             
  380.             long        cubeindx;
  381.             
  382.             cubeindx = gcurrent & ~0x3;
  383.             
  384.             if( gcurrent <= 0 )
  385.                 cubeindx = 0;
  386.             else
  387.                 cubeindx = ( ( gcurrent - 1 ) / 3 ) * 3;
  388.             
  389.             if( gpointcount < ( cubeindx + 3 ) ) return( false );
  390.             
  391.             tempcolor.space = gxGraySpace;
  392.             tempcolor.element.gray = 0;
  393.             tempcolor.profile = nil;
  394.         
  395.             tempcolor2.space = gxGraySpace;
  396.             tempcolor2.element.gray = 0xFFFF;
  397.             tempcolor2.profile = nil;
  398.         
  399.             EraseRect(& ((WindowPtr)doc)->portRect );
  400.             sh = NewCubic((cubic *) &dataPtr[ cubeindx ] ); GXSetShapeFill( sh, gxOpenFrameFill );
  401.             GXDrawShape( sh );
  402.             GXDisposeShape( sh );
  403.  
  404.             do
  405.                 {                    
  406.                     gxPoint        temppoint;
  407.                     gxPoint        savepoint;
  408.                     
  409.                     GXGetViewPortMouse( doc->vp, &temppoint );
  410.                     
  411.                     GXIgnoreGraphicsNotice( color_already_set );
  412.                     GXIgnoreGraphicsNotice( halftone_already_set );
  413.                     
  414.                     if( temppoint != *where )
  415.                         {
  416.                             savepoint = *where;
  417.                             
  418.                             *where = temppoint;
  419.                             
  420.                             // draw the new  cubic in xor mode
  421.                             
  422.                             sh = NewCubic((cubic *) &dataPtr[ cubeindx ] ); GXSetShapeFill( sh, gxOpenFrameFill );
  423.                             
  424.                             SetShapeFastXorTransfer( sh, &tempcolor2, &tempcolor );
  425.                             
  426.                             // erase the previous cubic by drawing in xor mode
  427.                             
  428.                             *where = savepoint;
  429.                             
  430.                             sh2 = NewCubic((cubic *) &dataPtr[ cubeindx ] ); GXSetShapeFill( sh2, gxOpenFrameFill );
  431.                             SetShapeFastXorTransfer( sh2, &tempcolor, &tempcolor2 );
  432.                             
  433.                             GXDrawShape( sh );            // erase first
  434.                             GXDrawShape( sh2 );            // draw now
  435.  
  436.                             GXDisposeShape( sh );
  437.                             GXDisposeShape( sh2 );
  438.                             
  439.                             *where = temppoint;
  440.                             
  441.                             DrawCubicNumbers( doc );
  442.                         }
  443.                     
  444.                     GXPopGraphicsNotice();
  445.                     GXPopGraphicsNotice();
  446.                                     
  447.                 } while( StillDown() );
  448.  
  449.             InvalRect(& ((WindowPtr)doc)->portRect );
  450.             
  451.             return( true );
  452.         }
  453.     else
  454.         {
  455.             return( false );
  456.         }
  457. }
  458.  
  459. #pragma segment Main
  460. void SetWorkRect(WindowPtr window,
  461.                                  Rect            *pinRect,
  462.                                  Rect            *limitRect)
  463. {
  464.     SetPort(window);
  465.     *limitRect = (*((WindowPeek) window)->contRgn)->rgnBBox;
  466.     GlobalToLocal(&TopLeft(*limitRect));
  467.     GlobalToLocal(&BotRight(*limitRect));
  468.     
  469.     *pinRect = *limitRect;
  470.     
  471.     InsetRect(limitRect,-5,-5);
  472.     InsetRect(pinRect,5,5);
  473.     return;
  474. }
  475. #pragma segment Main
  476. void Initialize( void )
  477. {
  478.     Handle                menuBar;
  479.     Ptr                        storage;
  480.     WindowPtr            window;
  481.     DocumentPeek     doc;
  482.     CursHandle        hCurs;
  483.  
  484.     MaxApplZone(); 
  485.     MoreMasters(); MoreMasters(); MoreMasters();
  486.  
  487.     gClient = GXNewGraphicsClient(nil, 800L * 1024L, nil);
  488.     GXEnterGraphics();
  489.  
  490.     SetGraphicsLibraryErrors();
  491.     SetGraphicsLibraryNotices();
  492.  
  493.     InitGraf((Ptr) &qd.thePort);
  494.     InitFonts();
  495.     InitWindows();
  496.     InitMenus();
  497.     TEInit();
  498.     InitDialogs(nil);
  499.     InitCursor();
  500.  
  501.     menuBar = GetNewMBar(rMenuBar);
  502.  
  503.     SetMenuBar(menuBar);
  504.     DisposHandle(menuBar);
  505.     AddResMenu(GetMHandle(mApple), 'DRVR');
  506.     DrawMenuBar();
  507.  
  508.     storage = NewPtr(sizeof( DocumentRecord ));
  509.     
  510.     if ( storage != nil ) 
  511.         {                        
  512.             window = GetNewWindow(rDocWindow, storage, (WindowPtr) -1);
  513.  
  514.             doc = (DocumentPeek) window;
  515.             doc->vp = GXNewWindowViewPort( window );
  516.             
  517.             GXIgnoreGraphicsNotice(transform_already_set);
  518.             SetDefaultViewPort( doc->vp );
  519.             GXPopGraphicsNotice();
  520.             
  521.             // gxInitialize all of the fields that have to do with the document
  522.             
  523.             doc->count = 0;
  524.             doc->data = (gxPoint **) NewHandle( 0 );        // there are no points
  525.             
  526.             ShowWindow(window);
  527.         }
  528.      else
  529.         DisposPtr(storage);            /* get rid of the storage if it is never used */
  530.         
  531.     hCurs = (CursHandle) GetResource('CURS',rHandCurs);
  532.     
  533.     if(hCurs != nil)
  534.         {
  535.             gHandCurs = **hCurs;
  536.             ReleaseResource((Handle) hCurs);
  537.         }
  538.     
  539.     gPolyMode = false;
  540. }
  541. #pragma segment Main
  542. void DrawControlHandle( gxPoint *where )
  543. {
  544.     gxRectangle        box;
  545.     gxShape             sh;
  546.     
  547.     box.left = where->x - ff( 2 );
  548.     box.top = where->y - ff( 2 );
  549.     box.right = where->x + ff( 2 );
  550.     box.bottom = where->y + ff( 2 );
  551.     
  552.     sh = GXNewRectangle( &box );
  553.  
  554.     GXDrawShape( sh );
  555.     GXDisposeShape( sh );
  556. }
  557.  
  558. void DrawCubicNumbers( DocumentPeek doc )
  559. {
  560.  
  561.     Str255    tempstring;
  562.     
  563.     Rect    erasebox = { 0, 0, 26, 170 };
  564.             
  565.     TextFont( geneva );
  566.     TextSize( 9 );
  567.     
  568.     // now calculate the number of quadratics that are needed to approximate this cubic
  569.     
  570.     sprintf( tempstring, "ticks: %d count: %d", gticks, gpointcount );
  571.     
  572.     EraseRect( &erasebox );
  573.     MoveTo( 5, 24 );
  574.     DrawString( c2pstr( tempstring ) );
  575.     
  576.     // we also need to calculate the error for the current cubic
  577.     
  578.     {
  579.         long             cubeindx;
  580.         extended     ax, ay, a, n;
  581.         extended     curveerror;
  582.         
  583.         long            count;
  584.         gxPoint            *dataPtr; 
  585.         
  586.         if( gcurrent <= 0 ) 
  587.             cubeindx = 0;
  588.         else
  589.             cubeindx = ( ( gcurrent - 1 ) / 3 ) * 3;
  590.         
  591.         if( gpointcount < ( cubeindx + 4 ) ) goto NotDoneYet;
  592.         
  593.         dataPtr = *(doc->data);
  594.         dataPtr = & dataPtr[ cubeindx ];
  595.         
  596.         ax = Fix2X( ( dataPtr[ 3 ].x - dataPtr[ 0 ].x ) + 3 * ( dataPtr[ 1 ].x - dataPtr[ 2 ].x ) );
  597.         ay = Fix2X( ( dataPtr[ 3 ].y - dataPtr[ 0 ].y ) + 3 * ( dataPtr[ 1 ].y - dataPtr[ 2 ].y ) );
  598.         
  599.         a = hypot( ax, ay );
  600.         
  601.         n = power( ( a / ( 20.0 * gerror ) ), 1.0 / 3.0 );
  602.         count = ceil( n );
  603.         
  604.         curveerror = a / ( 20 * count * count * count );
  605.         
  606.         sprintf( tempstring, "error: %.4lf  quads: %d", curveerror, count );
  607.         MoveTo( 5, 12 );
  608.         DrawString( c2pstr( tempstring ) );
  609.     }
  610. NotDoneYet:;
  611. }
  612.  
  613. void DrawCubicControl( gxShape sh )                // given a cubic it shows where the control points are
  614. {
  615.     short    count;
  616.     short    indx;
  617.     
  618.     fixed        cross[ 11 ];
  619.     gxPoint        where;
  620.     
  621.     gxShape    sh2;
  622.     
  623.     if( GXCountShapeContours( sh ) == 1 )
  624.         {            
  625.             count = GXCountShapePoints( sh, 1 ) - 2;
  626.             
  627.             cross[ 0 ] = 2;
  628.             cross[ 1 ] = 2;
  629.             cross[ 6 ] = 2;
  630.             
  631.             for( indx = 1; 0 < count; --count )
  632.                 {
  633.                     GetShapeIndexPoint( sh, ++indx, &where );
  634.                 
  635.                     cross[ 2 ] = where.x - ff( 3 );
  636.                     cross[ 3 ] = where.y - ff( 3 );
  637.                     cross[ 4 ] = where.x + ff( 3 );
  638.                     cross[ 5 ] = where.y + ff( 3 );
  639.                     cross[ 7 ] = where.x + ff( 3 );
  640.                     cross[ 8 ] = where.y - ff( 3 );
  641.                     cross[ 9 ] = where.x - ff( 3 );
  642.                     cross[ 10 ] = where.y + ff( 3 );
  643.                     
  644.                     sh2 = GXNewPolygons((gxPolygons *) & cross[ 0 ] );
  645.                     GXSetShapeFill( sh2, gxOpenFrameFill );
  646.                     GXDrawShape( sh2 );
  647.                     GXDisposeShape( sh2 );
  648.                 }
  649.         }
  650. }
  651.  
  652. #pragma segment Main
  653. void DrawWindow(WindowPtr window)
  654. {
  655.     DocumentPeek doc;
  656.     PenState    pen;
  657.     
  658.     doc = (DocumentPeek) window;
  659.     
  660.     SetPort(window);
  661.     GetPenState(&pen);
  662.     
  663.     PenNormal();
  664.     EraseRect(&window->portRect);
  665.     
  666.     gticks = TickCount();
  667.     
  668.     DrawCurves( doc->data );
  669.     gticks = TickCount() - gticks;
  670.     
  671.     DrawCubicNumbers( doc );
  672.  
  673.     // we now draw the cubic and its control points
  674.     
  675.     ForeColor(blackColor);
  676.     DrawMyGrow(window);
  677.     
  678.     SetPenState(&pen);
  679.     return;
  680. }
  681.  
  682. void DrawCurves( gxPoint **data )
  683. {
  684.     long         indx;
  685.     gxColor        tempcolor;
  686.     gxShape        sh;
  687.  
  688.     gxPoint        *dataPtr;
  689.  
  690.     tempcolor.space = gxRGBSpace;
  691.     tempcolor.profile = nil;
  692.     tempcolor.element.rgb.red = 0xFFFF;
  693.     tempcolor.element.rgb.green = tempcolor.element.rgb.blue = 0;
  694.  
  695.     HLock((Handle) data );
  696.  
  697.     dataPtr = *data;
  698.  
  699.     for( indx = 4; indx <= gpointcount; indx += 3 )
  700.         {
  701.             cubic *cube = & dataPtr[ indx - 4 ];
  702.             
  703.             sh = NewCubic( cube );     // first draw the reference cubic (in red)
  704.             GXSetShapeFill( sh, gxOpenFrameFill );
  705.             GXSetShapeColor( sh, &tempcolor );
  706.             GXDrawShape( sh );
  707.             GXDisposeShape( sh );
  708.             
  709.             sh = NewCubic2( cube, gcount );  GXSetShapeFill( sh, gxOpenFrameFill );
  710.         
  711.             GXDrawShape( sh );
  712.             DrawCubicControl( sh );
  713.             GXDisposeShape( sh );
  714.  
  715.             DrawControlHandle( &cube->a );
  716.             DrawControlHandle( &cube->b );
  717.             DrawControlHandle( &cube->c );
  718.             DrawControlHandle( &cube->d );
  719.         }
  720.         
  721.     HUnlock((Handle) data );
  722. }
  723.  
  724. #pragma segment Main
  725. void DrawMyGrow(WindowPtr window)
  726. {
  727.     Rect tempRect;
  728.     Rect drawRect;
  729.     PenState pen;
  730.     
  731.     SetPort(window);
  732.     GetPenState(&pen);
  733.     PenNormal();
  734.     
  735.     tempRect = (*((WindowPeek) window)->contRgn)->rgnBBox;
  736.     
  737.     drawRect.top = tempRect.bottom - 16;
  738.     drawRect.left = tempRect.right -16;
  739.     drawRect.bottom = tempRect.bottom;
  740.     drawRect.right = tempRect.right;
  741.     
  742.     GlobalToLocal(&TopLeft(drawRect));
  743.     GlobalToLocal(&BotRight(drawRect));
  744.     
  745.     EraseRect(&drawRect);
  746.     FrameRect(&drawRect);
  747.     
  748.     drawRect.right -= 2;
  749.     drawRect.bottom -= 2;
  750.     drawRect.left += 5;
  751.     drawRect.top += 5;
  752.     
  753.     FrameRect(&drawRect);
  754.     
  755.     drawRect.right -= 4;
  756.     drawRect.bottom -= 4;
  757.     drawRect.top -= 2;
  758.     drawRect.left -= 2;
  759.     
  760.     EraseRect(&drawRect);
  761.     FrameRect(&drawRect);
  762.     
  763.     SetPenState(&pen);
  764.     return;
  765. }
  766.  
  767.  
  768. #pragma segment Main
  769. void AdjustMenus( void )
  770. {
  771.     WindowPtr    window;
  772.     MenuHandle    menu;
  773.     Boolean        undo;
  774.  
  775.     window = FrontWindow();
  776.  
  777.     menu = GetMHandle(mEdit);
  778.     undo = false;
  779.     
  780.     if ( IsDAWindow(window) ) 
  781.         undo = true;
  782.     
  783.     if ( undo )
  784.         {
  785.             EnableItem(menu, iUndo);
  786.             EnableItem(menu, iCut);
  787.             EnableItem(menu, iCopy);
  788.             EnableItem(menu, iPaste);
  789.             EnableItem(menu, iClear);
  790.         }
  791.     else 
  792.         {
  793.             DisableItem(menu, iUndo);
  794.             DisableItem(menu, iCut);
  795.             DisableItem(menu, iCopy);
  796.             DisableItem(menu, iPaste);
  797.             DisableItem(menu, iClear);
  798.         }
  799.         
  800.     return;
  801. }
  802.  
  803. #pragma segment Main
  804. void DoMenuCommand(long menuResult)
  805. {
  806.     short        menuID;             /* the resource ID of the selected menu */
  807.     short        menuItem;           /* the item number of the selected menu */
  808.     short        itemHit;
  809.     Str255        daName;
  810.     short        daRefNum;
  811.     WindowPtr    window;
  812.     
  813.     window = FrontWindow();
  814.     
  815.     menuID = HiWrd(menuResult);    /* use macros for efficiency to... */
  816.     menuItem = LoWrd(menuResult);    /* get menu item number and menu number */
  817.     
  818.     switch ( menuID ) 
  819.         {
  820.             case mApple:
  821.                 switch ( menuItem ) 
  822.                     {
  823.                         case iAbout:
  824.                             itemHit = Alert(rAboutAlert, nil);
  825.                             break;
  826.                         default:
  827.                             GetItem(GetMHandle(mApple), menuItem, daName);
  828.                             daRefNum = OpenDeskAcc(daName);
  829.                             break;
  830.                     }
  831.                 break;
  832.                 
  833.             case mFile:
  834.                 if( menuItem == iOpen )
  835.                     {
  836.                     }
  837.                 else if( menuItem == iQuit )
  838.                     ExitApplication( window );
  839.                 break;
  840.             
  841.             case mEdit:
  842.                 SystemEdit(menuItem-1); 
  843.                 break;
  844.                 
  845.             case mClip:
  846.                 CheckItem( GetMHandle(mClip), gcount + 1, false );
  847.                 CheckItem( GetMHandle(mClip), menuItem, true );
  848.                 gcount = menuItem - 1;
  849.                 InvalRect(&window->portRect);
  850.                 break;
  851.                 
  852.             case mError:
  853.                 {
  854.                     if( menuItem != geindx )
  855.                         {
  856.                             CheckItem( GetMHandle(mError), geindx, false );
  857.                             CheckItem( GetMHandle(mError), menuItem, true );
  858.                             geindx = menuItem;
  859.                             InvalRect(&window->portRect);
  860.                             
  861.                             switch( menuItem )
  862.                                 {
  863.                                     case iOneTenth:
  864.                                         gerror = 0.01;
  865.                                         break;
  866.                                     case iOneQuater:
  867.                                         gerror = 0.25;
  868.                                         break;
  869.                                     case iOneHalf:
  870.                                         gerror = 0.5;
  871.                                         break;
  872.                                     case iThreeQuaters:
  873.                                         gerror = 0.75;
  874.                                         break;
  875.                                     case iOne:
  876.                                         gerror = 1.0;
  877.                                         break;
  878.                                     case iTwo:
  879.                                         gerror = 2.0;
  880.                                         break;
  881.                                     case iFour:
  882.                                         gerror = 4.0;
  883.                                         break;
  884.                                     case iEight:
  885.                                         gerror = 8.0;
  886.                                         break;
  887.                             }
  888.                     }
  889.                 }
  890.                 break;
  891.     }
  892.     HiliteMenu(0);                    /* unhighlight what MenuSelect (or MenuKey) hilited */
  893. }
  894.  
  895. #pragma segment Main
  896. void DoCloseWindow(WindowPtr window)
  897. {
  898.     if ( IsDAWindow(window) )
  899.         CloseDeskAcc(((WindowPeek) window)->windowKind);
  900.     else if ( IsAppWindow(window) ) 
  901.         ExitApplication( window );    
  902. }
  903.  
  904. #pragma segment Main
  905. Boolean IsAppWindow(WindowPtr window)
  906. {
  907.     short        windowKind;
  908.     
  909.     if ( window == nil )
  910.         return false;
  911.     else {    /* application windows have windowKinds >= userKind (8) or dialogKind (2) */
  912.         windowKind = ((WindowPeek) window)->windowKind;
  913.         return (windowKind >= userKind) || (windowKind == dialogKind);
  914.     }
  915. }
  916.  
  917. #pragma segment Main
  918. Boolean IsDAWindow(WindowPtr    window)
  919. {
  920.     if ( window == nil )
  921.         return false;
  922.     else    /* DA windows have negative windowKinds */
  923.         return ((WindowPeek) window)->windowKind < 0;
  924. }
  925.  
  926.  
  927. void ExitApplication( WindowPtr window )
  928. {    
  929.     DisposeWindow( window );
  930.     GXExitGraphics();
  931.     GXDisposeGraphicsClient(gClient);
  932.     ExitToShell();
  933. }
  934.  
  935. long CountQuadratics( const cubic *cube )
  936. {
  937.     long            count;
  938.     extended    a, n;
  939.     
  940.     extended ax;
  941.     extended ay;
  942.     
  943.     ax = Fix2X( - cube->a.x + 3 * cube->b.x - 3 * cube->c.x + cube->d.x );
  944.     ay = Fix2X( - cube->a.y + 3 * cube->b.y - 3 * cube->c.y + cube->d.y );
  945.     
  946.     a = hypot( ax, ay );
  947.     
  948.     n = power( ( a / ( 20.0 * gerror ) ), 1.0 / 3.0 );
  949.  
  950.     count = ceil( n );
  951.  
  952.     if( count <= 0 ) 
  953.         count += 1;
  954.  
  955.     return( count );
  956. }
  957.